<?php
class UdpIpDetect{
    public static function forWindows()
    {
        @exec("ipconfig", $array); #ipconfig /all
        if ($array)
            return $array;
        else {
            $ipconfig = $_SERVER["WINDIR"] . "\system32\ipconfig.exe";
            if (is_file($ipconfig))
                @exec($ipconfig, $array); #$ipconfig . " /all"
            else
                @exec($_SERVER["WINDIR"] . "\system\ipconfig.exe /all", $array);
            return $array;
        }
    }
    public static function forLinux()
    {
        @exec("ifconfig", $array); #ifconfig -a
        return $array;
    }

    public static function localIp($loopback=true){
        $array = DIRECTORY_SEPARATOR === '\\' ? self::forWindows() : self::forLinux();
        $list = [];
        foreach ($array as $v){
            if(strpos($v,'inet')!==false || strpos($v,'IP')!==false){
                if (preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/", $v, $matches)) {
                    if($matches[0]=='127.0.0.1' && !$loopback) continue;
                    $list[] = $matches[0];
                }
            }
        }
        return $list;
    }

    #udp 发现服务
    /**
     * @param string $sendKey 获取ip指令 REPORT_IP
     * @param int $sendPort 指定端口
     * @param string $address 指定ip
     * @return array
     */
    public static function broadCast($sendKey, $sendPort, $address='')
    {
        set_error_handler(function(){}); #禁用错误处理
        // 创建udp socket
        $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
        $address && socket_bind($socket, $address); #绑定指定ip
        socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);
        // 广播
        $buffer = LogPackage::encode($sendKey); #数据指令
        socket_sendto($socket, $buffer, strlen($buffer), 0, '255.255.255.255', $sendPort);
        // 超时相关
        $time_start = microtime(true);
        $global_timeout = 1; #循环结果读取超时 秒
        $ip_list = [];
        $recv_timeout = array('sec' => 0, 'usec' => 8000); #0秒8毫秒
        socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $recv_timeout);

        // 循环读数据
        while (microtime(true) - $time_start < $global_timeout) {
            $buf = $host = $port = '';
            if (@socket_recvfrom($socket, $buf, 1024, 0, $host, $port)) {
                $data = LogPackage::decode($buf);
                if (strpos($data['msg'],'OK:')===0) {
                    $ip_list['udp://'.$host . ':' . $port] = 1;
                    $ip_list['tcp://'.$host . ':' . substr($data['msg'], 3)] = 1;
                }
            }
            #message:socket_recvfrom(): unable to recvfrom [10060]: 由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。
        }
        socket_close($socket);
        restore_error_handler(); #还原错误处理
        return $ip_list;
    }
}